//
// Created by jerry on 2021/4/6.
//
#include <stdio.h>
#include <stdlib.h>

#include "queue.h"

#define DEBUG 1
#define LOGD(fmt, ...) {if (DEBUG == 1 ) printf("[D][%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__);}

/*************************************************************************
* Function:    struct QUEUE *queue_init()
* Description: 初始化队列
* Input:       无
* Return:      struct QUEUE * 初始化完成的队列
* Others:      NULL
**************************************************************************/
struct QUEUE *queue_init()
{
    LOGD("queue init.");

    struct QUEUE *queue = (struct QUEUE *)calloc(1, sizeof(struct QUEUE)); // 申请QUEUE空间
    queue->qMutex = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t)); // 申请Mutex空间
    pthread_mutex_init(queue->qMutex, NULL); // 初始化Mutex
    queue->qCount = 0;  // 初始化count数值
    queue->head = NULL; // 消息节点置空

    /* 回调函数指针赋值 */
    queue->ENQUEUE           = enqueue;           // 入列
    queue->DEQUEUE           = dequeue;           // 出列
    queue->QUEUE_COUNT       = queue_count;       // 队列长度
    queue->QUEUE_COUNT_DEBUG = queue_count_debug; // 队列长度
    queue->QUEUE_FREE        = queue_free;        // 释放对列

    return queue;
}

/*************************************************************************
* Function:    void enqueue(struct QUEUE *queue,
*                                     struct USER_INFO *userInfo)
* Description: 数据压入队列
* Input:
*              struct QUEUE *queue          队列句柄
*              struct USER_INFO *userInfo   需要入列的数据
* Return:      NULL
* Others:      NULL
**************************************************************************/
void enqueue(struct QUEUE *queue, struct USER_INFO *userInfo)
{
    if (queue == NULL)
    {
        return ;
    }

    if (userInfo == NULL)
    {
        return ;
    }
    
    pthread_mutex_lock(queue->qMutex); // 上锁

    /* 为新来的数据申请空间且赋值 */
    struct NODES *newNodes = (struct NODES *)calloc(1, sizeof(struct NODES));
    newNodes->userInfo = userInfo; // 赋值

    /* 数据入列 */
    if (!queue->head)
    {
        queue->head    = newNodes;
        newNodes->next = NULL;
    }
    else
    {
        struct NODES *tmp = queue->head;
        while (tmp->next)
        {
            tmp = tmp->next;
        }

        tmp->next      = newNodes;
        newNodes->next = NULL;
    }

    ++ queue->qCount; // 队列长度 + 1
    pthread_mutex_unlock(queue->qMutex); // 解锁
}

/*************************************************************************
* Function:    struct USER_INFO *dequeue(struct QUEUE *queue)
* Description: 数据出列
* Input:
*              struct QUEUE *queue 队列句柄
* Return:      struct USER_INFO *  队列中的数据
* Others:      NULL
**************************************************************************/
struct USER_INFO *dequeue(struct QUEUE *queue)
{
    if (queue == NULL)
    {
        return NULL;
    }

    pthread_mutex_lock(queue->qMutex); // 上锁

    /* head为空即队列中没有数据 */
    if (!queue->head)
    {
        pthread_mutex_unlock(queue->qMutex);
        return NULL;
    }

    /* 取出头部数据 */
    struct NODES *tmp = queue->head;
    queue->head       = tmp->next;
    tmp->next         = NULL;

    struct USER_INFO *userInfo = tmp->userInfo;
    free(tmp);
    tmp = NULL;

    -- queue->qCount;
    pthread_mutex_unlock(queue->qMutex);

    return userInfo;
}


/*************************************************************************
* Function:    size_t queue_count(struct QUEUE *queue)
* Description: 获取队列长度
* Input:
*              struct QUEUE *queue 队列句柄
* Return:      size_t 队列实际长度
* Others:      NULL
**************************************************************************/
size_t queue_count(struct QUEUE *queue)
{
    if (queue == NULL)
    {
        return 0;
    }

    pthread_mutex_lock(queue->qMutex); // 上锁

    size_t count = queue->qCount;
    pthread_mutex_unlock(queue->qMutex);
    return count;
}

/*************************************************************************
* Function:    size_t queue_count_debug(struct QUEUE *queue)
* Description: 获取队列长度
* Input:
*              struct QUEUE *queue 队列句柄
* Return:      size_t 队列实际长度
* Others:      NULL
**************************************************************************/
size_t queue_count_debug(struct QUEUE *queue)
{
    if (queue == NULL)
    {
        return 0;
    }

    pthread_mutex_lock(queue->qMutex); // 上锁

    size_t count = 0;
    struct NODES *tmp = queue->head;
    while (tmp)
    {
        tmp = tmp->next;
        ++ count;
    }

    pthread_mutex_unlock(queue->qMutex);
    return count;
}

/*************************************************************************
* Function:    void queue_free(struct QUEUE **queue, bool freeData)
* Description: 释放队列
* Input:
*              struct QUEUE **queue 队列句柄
*              bool freeData        是否需要释放队列中的数据(如果结构体中的数据申请了空间至true)
* Return:      NULL
* Others:      NULL
**************************************************************************/
void queue_free(struct QUEUE **queue, bool freeData)
{
    pthread_mutex_lock((*queue)->qMutex); // 上锁

    struct NODES *tmp = NULL;

    while ((*queue)->head)
    {
        tmp = (*queue)->head;
        (*queue)->head = tmp->next;
        tmp->next = NULL;

        if (freeData) // 若tmp->userInfo->name申请过空间，则需要释放，否则freeData至false
        {
            free(tmp->userInfo->name);
            tmp->userInfo->name = NULL;
            free(tmp->userInfo);
            tmp->userInfo = NULL;
        }
        free(tmp);
        tmp = NULL;
    }

    /* 释放锁 */
    pthread_mutex_unlock((*queue)->qMutex);
    pthread_mutex_destroy((*queue)->qMutex);
    free((*queue)->qMutex);
    (*queue)->qMutex = NULL;

    /* 释放整个队列 */
    free(*queue);
    *queue = NULL;
}